package core

import (
	"errors"
	"gitee.com/hongzhaomin/gspring/iface"
	"gitee.com/hongzhaomin/gspring/tools"
	"reflect"
	"sync"
	"sync/atomic"
	"time"
)

func NewAbstractApplicationContext(child, parent iface.ApplicationContext) *AbstractApplicationContext {
	context := new(AbstractApplicationContext)
	context.ApplicationContext = child
	context.parent = parent
	context.startupShutdownMonitor = new(sync.Mutex)
	context.registerBeans = make([]any, 0, 256)
	context.beanFactoryPostProcessors = make([]iface.BeanFactoryPostProcessor, 0, 16)
	return context
}

// ===========================================================================
// ======================= AbstractApplicationContext ========================
// ===========================================================================
var _ iface.BeanFactory = (*AbstractApplicationContext)(nil)
var _ iface.ApplicationContext = (*AbstractApplicationContext)(nil)

// AbstractApplicationContext 应用容器抽象实现类
// 注意：这是一个真正意义上的抽象类，需要继承该抽象类的子类，必须实现以下两个方法，否则会panic：
//
//	iface.ApplicationContext.GetBeanFactory()
//	iface.ApplicationContext.RefreshBeanFactory()
type AbstractApplicationContext struct {
	iface.ApplicationContext // 子类：如果A类继承了此抽象类，该属性就赋值A类对象

	parent                    iface.ApplicationContext
	startupShutdownMonitor    *sync.Mutex
	startupDate               time.Time
	active                    atomic.Bool
	closed                    atomic.Bool
	registerBeans             []any
	beanFactoryPostProcessors []iface.BeanFactoryPostProcessor
}

// child 所有的方法都用子类对象调用，这样子类可以重写任意方法（设计抽象类推荐使用这种方式）
// 这样设计的好处是不会有坑，防止子类重写了某个方法，父类还是用自身对象调用，这样子类重写的方法就调用不到了
func (my *AbstractApplicationContext) child() iface.ApplicationContext {
	if my.ApplicationContext != nil {
		return my.ApplicationContext
	}
	return my
}

func (my *AbstractApplicationContext) RegisterOriginBeans(registerBeans []any) {
	if len(registerBeans) > 0 {
		my.registerBeans = append(my.registerBeans, registerBeans...)
	}
}

func (my *AbstractApplicationContext) AddBeanFactoryPostProcessor(postProcessor iface.BeanFactoryPostProcessor) {
	tools.Assert().NotNil(postProcessor, "BeanFactoryPostProcessor must not be nil")
	my.beanFactoryPostProcessors = append(my.beanFactoryPostProcessors, postProcessor)
}

func (my *AbstractApplicationContext) GetBeanFactoryPostProcessors() []iface.BeanFactoryPostProcessor {
	return my.beanFactoryPostProcessors
}

func (my *AbstractApplicationContext) LoadBeanDefinitions(beanFactory iface.ListableBeanFactory) {
	for _, bean := range my.registerBeans {
		bd := NewBeanDefinitionBuilder().Default(bean)
		beanFactory.(iface.BeanDefinitionRegistry).RegisterBeanDefinition(bd.GetBeanName(), bd)
	}
}

func (my *AbstractApplicationContext) Refresh() {
	my.startupShutdownMonitor.Lock()
	defer my.startupShutdownMonitor.Unlock()

	// 准备刷新context
	my.child().PrepareRefresh()
	my.child().AddBeanFactoryPostProcessor(new(StructPointResolvedPostProcessor))
	my.child().AddBeanFactoryPostProcessor(new(ConfigurationPostProcessor))

	// 绑定BeanFactory
	beanFactory := my.child().ObtainFreshBeanFactory()

	// BeanFactory的准备工作
	my.child().PrepareBeanFactory(beanFactory)

	// 允许子类context注册BeanFactoryPostProcessor
	my.child().PostProcessorBeanFactory(beanFactory)

	// 加载bean定义信息
	my.child().LoadBeanDefinitions(beanFactory)

	// 执行BeanFactoryPostProcessor方法
	my.child().InvokeBeanFactoryPostProcessors(beanFactory)

	// 注册BeanPostProcessor
	my.child().RegisterBeanPostProcessors(beanFactory)

	// 实例化剩下的所有bean对象
	my.child().FinishBeanFactoryInitialization(beanFactory)
}

func (my *AbstractApplicationContext) GetParent() iface.ApplicationContext {
	return my.parent
}

func (my *AbstractApplicationContext) SetParent(parent iface.ApplicationContext) {
	my.parent = parent
}

func (my *AbstractApplicationContext) PrepareRefresh() {
	my.startupDate = time.Now()
	my.closed.Store(false)
	my.active.Store(true)
}

func (my *AbstractApplicationContext) ObtainFreshBeanFactory() iface.ListableBeanFactory {
	// 调用子类RefreshBeanFactory()和GetBeanFactory()方法
	my.child().RefreshBeanFactory()
	return my.child().GetBeanFactory()
}

func (my *AbstractApplicationContext) PrepareBeanFactory(beanFactory iface.ListableBeanFactory) {
	// 添加bean的依赖注入后置处理器
	beanFactory.AddBeanPostProcessor(NewCommonAnnotationBeanPostProcessor(beanFactory))
}

// PostProcessorBeanFactory 允许子类context注册BeanFactoryPostProcessor
func (my *AbstractApplicationContext) PostProcessorBeanFactory(beanFactory iface.ListableBeanFactory) {
	// 留给子类扩展实现
}

func (my *AbstractApplicationContext) InvokeBeanFactoryPostProcessors(beanFactory iface.ListableBeanFactory) {
	postProcessors := my.child().GetBeanFactoryPostProcessors()
	processorBeanNameSet := make(map[string]struct{}, 256)
	// 将processor.BeanDefinitionRegistryPostProcessor的增强器挑选出来先执行BeanDefinition的注册逻辑
	registry, implementRegistry := beanFactory.(iface.BeanDefinitionRegistry)
	if implementRegistry {
		needRepeatCall := false
		bdCountFirst := registry.GetBeanDefinitionCount()
		// BeanFactoryPostProcessor分为BeanDefinition的注册器和增强器两类：
		// 注册器是用来新增BeanDefinition的，增强器是用来修改BeanDefinition的
		repeatableCallRegistryPostProcessors := make(map[iface.BeanDefinitionRegistryPostProcessor]struct{}, 16)
		registryPostProcessors := make([]iface.BeanDefinitionRegistryPostProcessor, 0, 16)
		regularPostProcessors := make([]iface.BeanFactoryPostProcessor, 0, 16)
		for _, beanFactoryPostProcessor := range postProcessors {
			if registryPostProcessor, ok := beanFactoryPostProcessor.(iface.BeanDefinitionRegistryPostProcessor); ok {
				// 执行注册方法，注册BeanDefinition
				registryPostProcessor.PostProcessorBeanDefinitionRegistry(registry)
				registryPostProcessors = append(registryPostProcessors, registryPostProcessor)
				if registryPostProcessor.RepeatableCall() {
					repeatableCallRegistryPostProcessors[registryPostProcessor] = struct{}{}
				}
			} else {
				regularPostProcessors = append(regularPostProcessors, beanFactoryPostProcessor)
			}
		}
		// 如果这里需要重复执行，那么下面第一次判断肯定也是需要重复执行的
		needRepeatCall = registry.GetBeanDefinitionCount() > bdCountFirst

		// 从BeanFactory中取出bd注册增强器执行注册逻辑
		for {
			breakFlag := true
			currentRegistryProcessors := make([]iface.BeanDefinitionRegistryPostProcessor, 0, 16)
			processorNames := beanFactory.GetBeanNamesForType(iface.RefTypeOfBeanDefinitionRegistryPostProcessor)
			for _, processorName := range processorNames {
				// 只要有新增BeanDefinitionRegistryPostProcessor，就需要重复执行
				if _, contains := processorBeanNameSet[processorName]; !contains {
					getProcessor := beanFactory.GetBean(processorName,
						iface.RefTypeOfBeanDefinitionRegistryPostProcessor).(iface.BeanDefinitionRegistryPostProcessor)
					currentRegistryProcessors = append(currentRegistryProcessors, getProcessor)
					if getProcessor.RepeatableCall() {
						repeatableCallRegistryPostProcessors[getProcessor] = struct{}{}
					}
					processorBeanNameSet[processorName] = struct{}{}
					breakFlag = false
				}
				registryPostProcessors = append(registryPostProcessors, currentRegistryProcessors...)
				for _, registryProcessor := range currentRegistryProcessors {
					// 执行注册方法，注册BeanDefinition
					registryProcessor.PostProcessorBeanDefinitionRegistry(registry)
				}
			}

			// 执行可重复调用的注册增强器，只要有新增BeanDefinition，就需要重复执行
			bdCountRepeatBefore := registry.GetBeanDefinitionCount()
			needRepeatCall = bdCountRepeatBefore > bdCountFirst
			if needRepeatCall {
				bdCountFirst = bdCountRepeatBefore
				for repeatableCallProcessor := range repeatableCallRegistryPostProcessors {
					// 执行注册方法，注册BeanDefinition
					repeatableCallProcessor.PostProcessorBeanDefinitionRegistry(registry)
				}
			}
			bdCountRepeatAfter := registry.GetBeanDefinitionCount()

			if breakFlag && bdCountRepeatBefore == bdCountRepeatAfter {
				break
			}
		}

		// 最后再执行BeanFactoryPostProcessor的后置处理器增强逻辑
		invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory)
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory)
	} else {
		invokeBeanFactoryPostProcessors(postProcessors, beanFactory)
	}

	// 从BeanFactory中取出BeanFactoryPostProcessor的后置处理器，执行增强逻辑
	currentProcessors := make([]iface.BeanFactoryPostProcessor, 0)
	processorNames := beanFactory.GetBeanNamesForType(iface.RefTypeOfBeanFactoryPostProcessor)
	for _, processorName := range processorNames {
		getProcessor := beanFactory.GetBean(processorName, iface.RefTypeOfBeanFactoryPostProcessor)
		if _, contains := processorBeanNameSet[processorName]; !contains {
			currentProcessors = append(currentProcessors, getProcessor.(iface.BeanFactoryPostProcessor))
		}
	}
	invokeBeanFactoryPostProcessors(currentProcessors, beanFactory)
}

func (my *AbstractApplicationContext) RegisterBeanPostProcessors(beanFactory iface.ListableBeanFactory) {
	postProcessorNames := beanFactory.GetBeanNamesForType(iface.RefTypeOfBeanPostProcessor)
	for _, ppName := range postProcessorNames {
		beanPostProcessor := beanFactory.GetBeanByName(ppName).(iface.BeanPostProcessor)
		beanFactory.AddBeanPostProcessor(beanPostProcessor)
	}
}

func (my *AbstractApplicationContext) FinishBeanFactoryInitialization(beanFactory iface.ListableBeanFactory) {
	for _, beanName := range beanFactory.GetBeanDefinitionNames() {
		beanFactory.GetBeanByName(beanName)
	}
}

// 以下两个方法抽象类不实现，留给子类实现
// RefreshBeanFactory 子类必须实现，执行配置加载
//func (my *AbstractApplicationContext) RefreshBeanFactory() {
//	//TODO implement me
//	panic("implement me")
//}

// GetBeanFactory 子类必须实现，获取BeanFactory
//func (my *AbstractApplicationContext) GetBeanFactory() iface.ListableBeanFactory {
//	//TODO implement me
//	panic("implement me")
//}

func (my *AbstractApplicationContext) Close() error {
	my.startupShutdownMonitor.Lock()
	defer my.startupShutdownMonitor.Unlock()
	if my.active.Load() && my.closed.CompareAndSwap(false, true) {

		my.destroyBeans()

		my.active.Store(false)
	}
	return nil
}

func (my *AbstractApplicationContext) IsActive() bool {
	return my.active.Load()
}

func (my *AbstractApplicationContext) destroyBeans() {
	my.GetBeanFactory().DestroySingletons()
}

// =============Start============= 实现iface.BeanFactory接口 ===========Start===========

func (my *AbstractApplicationContext) GetBeanByName(beanName string) any {
	my.assertBeanFactoryActive()
	return my.child().GetBeanFactory().GetBeanByName(beanName)
}

func (my *AbstractApplicationContext) GetBean(beanName string, rt reflect.Type) any {
	my.assertBeanFactoryActive()
	return my.child().GetBeanFactory().GetBean(beanName, rt)
}

func (my *AbstractApplicationContext) GetBeanByType(beanType any) any {
	my.assertBeanFactoryActive()
	return my.child().GetBeanFactory().GetBeanByType(beanType)
}

func (my *AbstractApplicationContext) GetBeanByRt(refType reflect.Type) any {
	my.assertBeanFactoryActive()
	return my.child().GetBeanFactory().GetBeanByRt(refType)
}

func (my *AbstractApplicationContext) GetBeans(refType reflect.Type) []any {
	my.assertBeanFactoryActive()
	return my.child().GetBeanFactory().GetBeans(refType)
}

func (my *AbstractApplicationContext) assertBeanFactoryActive() {
	if !my.active.Load() {
		if my.closed.Load() {
			panic(errors.New("gspring application context has been closed already"))
		} else {
			panic(errors.New("gspring application context has not been refreshed yet"))
		}
	}
}

//func (my *AbstractApplicationContext) subClass() iface.ApplicationContext {
//	return my.ApplicationContext
//}

// =============End============= 实现iface.BeanFactory接口 ===========End===============

// ====================Start==================== 函数 ==================Start=================

func invokeBeanFactoryPostProcessors[T iface.BeanFactoryPostProcessor](postProcessors []T, beanFactory iface.ListableBeanFactory) {
	for _, postProcessor := range postProcessors {
		postProcessor.PostProcessBeanFactory(beanFactory)
	}
}

// ====================End==================== 函数 ==================End======================
